<script setup lang="ts">
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue';

import { ElButton, ElDialog, ElIcon, ElMessage } from 'element-plus';

// 导入自定义组件
import ChartCard from './components/ChartCard.vue';
// 导入配置组件
import ChartCardConfig from './components/config/ChartCardConfig.vue';
import InfoCardConfig from './components/config/InfoCardConfig.vue';
import TodoCardConfig from './components/config/TodoCardConfig.vue';
import WeatherCardConfig from './components/config/WeatherCardConfig.vue';
import InfoCard from './components/InfoCard.vue';
import TodoCard from './components/TodoCard.vue';
import WeatherCard from './components/WeatherCard.vue';
// 导入新拆分的组件
import Toolbar from './components/Toolbar.vue';
import ComponentPanel from './components/ComponentPanel.vue';
import Canvas from './components/Canvas.vue';

interface LayoutItem {
  id: string;
  type: string;
  gridX: number; // 栅格X位置 (0-23)
  gridY: number; // 栅格Y位置 (0-∞)
  gridWidth: number; // 栅格宽度 (1-24)
  gridHeight: number; // 栅格高度 (1-∞)
  config?: Record<string, any>;
}

interface ComponentDefinition {
  type: string;
  name: string;
  description: string;
  minGridWidth: number; // 最小栅格宽度
  minGridHeight: number; // 最小栅格高度
  defaultGridWidth: number; // 默认栅格宽度
  defaultGridHeight: number; // 默认栅格高度
  defaultConfig: Record<string, any>;
}

// 栅格系统配置
const GRID_COLUMNS = 24;

// 响应式数据
const isEditMode = ref(false);
const layoutItems = ref<LayoutItem[]>([]);
const configDialogVisible = ref(false);
const currentConfigItem = ref<LayoutItem | null>(null);
const workspaceRef = ref<HTMLElement>();
const draggedItem = ref<LayoutItem | null>(null);
const dragOffset = ref({ x: 0, y: 0 });
const resizingItem = ref<LayoutItem | null>(null);
const resizeHandle = ref('');
const selectedItem = ref<LayoutItem | null>(null);
const layoutBackup = ref<LayoutItem[]>([]);

// 计算栅格大小 - 画布占满容器宽度，栅格单元格是正方形
const canvasWidth = computed(() => {
  // 依赖forceRefresh来强制重新计算
  forceRefresh.value;
  if (!workspaceRef.value) return 1200;
  return workspaceRef.value.clientWidth - 32; // 减去容器的padding (p-4 = 16px * 2)
});

const gridUnitSize = computed(() => {
  // 栅格单元格是正方形，宽度 = 画布宽度 / 24
  return canvasWidth.value / GRID_COLUMNS;
});

// 可用组件定义
const availableComponents: ComponentDefinition[] = [
  {
    type: 'user-stats',
    name: '用户统计',
    description: '显示用户相关数据',
    minGridWidth: 4,
    minGridHeight: 4,
    defaultGridWidth: 6,
    defaultGridHeight: 6,
    defaultConfig: {
      title: '总用户数',
      value: '12,345',
      unit: '人',
      trend: 'up',
      trendValue: '12%',
      description: '较上月增长',
    },
  },
  {
    type: 'revenue-stats',
    name: '收入统计',
    description: '显示收入数据',
    minGridWidth: 4,
    minGridHeight: 4,
    defaultGridWidth: 6,
    defaultGridHeight: 6,
    defaultConfig: {
      title: '月收入',
      value: '¥89,432',
      unit: '',
      trend: 'up',
      trendValue: '8.5%',
      description: '较上月增长',
    },
  },
  {
    type: 'order-stats',
    name: '订单统计',
    description: '显示订单相关数据',
    minGridWidth: 4,
    minGridHeight: 4,
    defaultGridWidth: 6,
    defaultGridHeight: 6,
    defaultConfig: {
      title: '今日订单',
      value: '234',
      unit: '单',
      trend: 'down',
      trendValue: '2.1%',
      description: '较昨日下降',
    },
  },
  {
    type: 'sales-trend',
    name: '销售趋势',
    description: '显示销售数据趋势图表',
    minGridWidth: 8,
    minGridHeight: 8,
    defaultGridWidth: 12,
    defaultGridHeight: 10,
    defaultConfig: {
      title: '销售趋势',
      chartType: 'area',
      data: [120, 200, 150, 80, 70, 110, 130, 180, 160, 140, 200, 180],
      xAxisData: [
        '1月',
        '2月',
        '3月',
        '4月',
        '5月',
        '6月',
        '7月',
        '8月',
        '9月',
        '10月',
        '11月',
        '12月',
      ],
      seriesName: '销售额',
    },
  },
  {
    type: 'channel-analysis',
    name: '渠道分析',
    description: '显示各渠道数据分布',
    minGridWidth: 6,
    minGridHeight: 8,
    defaultGridWidth: 8,
    defaultGridHeight: 10,
    defaultConfig: {
      title: '流量来源',
      chartType: 'pie',
      data: [
        { value: 1048, name: '搜索引擎' },
        { value: 735, name: '直接访问' },
        { value: 580, name: '邮件营销' },
        { value: 484, name: '社交媒体' },
        { value: 300, name: '其他渠道' },
      ],
      seriesName: '访问量',
    },
  },
  {
    type: 'daily-tasks',
    name: '今日任务',
    description: '显示今日待办任务',
    minGridWidth: 6,
    minGridHeight: 8,
    defaultGridWidth: 8,
    defaultGridHeight: 12,
    defaultConfig: {
      title: '今日任务',
      items: [
        {
          title: '完成项目报告',
          description: '整理本周项目进度',
          completed: false,
          priority: 'high',
          dueDate: '2024-12-20 18:00:00',
        },
        {
          title: '客户会议',
          description: '与客户讨论需求',
          completed: false,
          priority: 'medium',
          dueDate: '2024-12-20 14:00:00',
        },
        {
          title: '代码审查',
          description: '审查团队提交的代码',
          completed: true,
          priority: 'medium',
        },
      ],
    },
  },
  {
    type: 'weather-info',
    name: '天气信息',
    description: '显示当前城市天气',
    minGridWidth: 5,
    minGridHeight: 8,
    defaultGridWidth: 6,
    defaultGridHeight: 10,
    defaultConfig: {
      city: '北京',
      showForecast: true,
    },
  },
];

// 栅格转换函数 - 统一使用正方形栅格
const gridToPixel = (gridValue: number) => {
  return gridValue * gridUnitSize.value;
};

const pixelToGrid = (pixelValue: number) => {
  return Math.round(pixelValue / gridUnitSize.value);
};

// 碰撞检测函数
const checkCollision = (
  item: LayoutItem,
  newX: number,
  newY: number,
  newWidth?: number,
  newHeight?: number,
) => {
  const width = newWidth || item.gridWidth;
  const height = newHeight || item.gridHeight;

  return layoutItems.value.some((otherItem) => {
    if (otherItem.id === item.id) return false; // 不与自己比较

    // 检查是否重叠
    const noOverlapX =
      newX >= otherItem.gridX + otherItem.gridWidth ||
      newX + width <= otherItem.gridX;
    const noOverlapY =
      newY >= otherItem.gridY + otherItem.gridHeight ||
      newY + height <= otherItem.gridY;

    return !(noOverlapX || noOverlapY); // 如果没有不重叠，则表示重叠
  });
};

// 方法
// 检查是否有未保存的修改
const hasUnsavedChanges = () => {
  // 如果还没有进入过设计模式，layoutBackup 为空，不算有修改
  if (layoutBackup.value.length === 0) return false;
  return (
    JSON.stringify(layoutItems.value) !== JSON.stringify(layoutBackup.value)
  );
};

const toggleEditMode = () => {
  if (isEditMode.value) {
    // 退出设计模式 - 恢复到进入设计模式前的状态
    selectedItem.value = null;

    // 恢复布局
    if (layoutBackup.value.length > 0) {
      layoutItems.value = JSON.parse(JSON.stringify(layoutBackup.value));
      ElMessage.info('已恢复到进入设计模式前的状态');
    }

    isEditMode.value = false;
  } else {
    // 进入设计模式时，备份当前布局
    layoutBackup.value = JSON.parse(JSON.stringify(layoutItems.value));
    isEditMode.value = true;
  }
};

// 从组件库拖拽
const handleDragStart = (event: DragEvent, component: ComponentDefinition) => {
  if (event.dataTransfer) {
    event.dataTransfer.setData('application/json', JSON.stringify(component));
  }
};

const handleDragOver = (event: DragEvent) => {
  event.preventDefault();
};

const handleDrop = (event: DragEvent) => {
  event.preventDefault();
  if (event.dataTransfer && workspaceRef.value) {
    try {
      const component = JSON.parse(
        event.dataTransfer.getData('application/json'),
      );
      const rect = workspaceRef.value.getBoundingClientRect();
      const x = event.clientX - rect.left;
      const y = event.clientY - rect.top;
      addComponent(component, x, y);
    } catch (error) {
      console.error('Failed to parse dropped component:', error);
    }
  }
};

const addComponent = (component: ComponentDefinition, x: number, y: number) => {
  const gridX = Math.max(
    0,
    Math.min(pixelToGrid(x), GRID_COLUMNS - component.defaultGridWidth),
  );
  let gridY = Math.max(0, pixelToGrid(y));

  const newItem: LayoutItem = {
    id: `${component.type}-${Date.now()}`,
    type: component.type,
    gridX,
    gridY,
    gridWidth: component.defaultGridWidth,
    gridHeight: component.defaultGridHeight,
    config: { ...component.defaultConfig },
  };

  // 如果位置有冲突，寻找最近的空位
  while (checkCollision(newItem, gridX, gridY)) {
    gridY += 1; // 向下移动一行
    if (gridY > 100) {
      // 防止无限循环
      ElMessage.warning('画布空间不足，请手动调整组件位置');
      break;
    }
  }

  newItem.gridX = gridX;
  newItem.gridY = gridY;
  layoutItems.value.push(newItem);
  ElMessage.success(`已添加${component.name}`);
};

// 拖拽移动组件
const startDrag = (event: MouseEvent, item: LayoutItem) => {
  if (!isEditMode.value) return;

  // 如果点击的是控制按钮，不启动拖拽
  const target = event.target as HTMLElement;
  if (target.closest('.item-controls')) {
    return;
  }

  // 选中组件
  selectItem(item);

  draggedItem.value = item;
  const itemElement = target.closest('.layout-item') as HTMLElement;
  const rect = itemElement.getBoundingClientRect();

  dragOffset.value = {
    x: event.clientX - rect.left,
    y: event.clientY - rect.top,
  };

  document.addEventListener('mousemove', handleDragMove);
  document.addEventListener('mouseup', handleDragEnd);
  event.preventDefault();
};

const handleDragMove = (event: MouseEvent) => {
  if (!draggedItem.value || !workspaceRef.value) return;

  const rect = workspaceRef.value.getBoundingClientRect();
  const x = event.clientX - rect.left - dragOffset.value.x;
  const y = event.clientY - rect.top - dragOffset.value.y;

  const gridX = Math.max(
    0,
    Math.min(pixelToGrid(x), GRID_COLUMNS - draggedItem.value.gridWidth),
  );
  const gridY = Math.max(0, pixelToGrid(y));

  // 拖拽时允许跨越其他组件，不进行碰撞检测
  draggedItem.value.gridX = gridX;
  draggedItem.value.gridY = gridY;
};

const handleDragEnd = () => {
  if (draggedItem.value) {
    // 拖拽结束时检查碰撞，如果有碰撞则寻找最近的空位
    const item = draggedItem.value;
    let finalX = item.gridX;
    let finalY = item.gridY;

    // 如果当前位置有碰撞，寻找最近的空位
    if (checkCollision(item, finalX, finalY)) {
      let found = false;

      // 先尝试向下寻找空位
      for (let y = finalY; y <= finalY + 10 && !found; y++) {
        if (!checkCollision(item, finalX, y)) {
          finalY = y;
          found = true;
        }
      }

      // 如果向下没找到，尝试向右寻找
      if (!found) {
        for (
          let x = finalX + 1;
          x <= GRID_COLUMNS - item.gridWidth && !found;
          x++
        ) {
          if (!checkCollision(item, x, finalY)) {
            finalX = x;
            found = true;
          }
        }
      }

      // 如果还没找到，尝试向上寻找
      if (!found) {
        for (let y = Math.max(0, finalY - 10); y < finalY && !found; y++) {
          if (!checkCollision(item, finalX, y)) {
            finalY = y;
            found = true;
          }
        }
      }

      // 如果都没找到合适位置，显示警告
      if (!found) {
        ElMessage.warning('无法放置到此位置，组件已移动到最近的空位');
        // 寻找画布中任意空位
        outerLoop: for (let y = 0; y < 50; y++) {
          for (let x = 0; x <= GRID_COLUMNS - item.gridWidth; x++) {
            if (!checkCollision(item, x, y)) {
              finalX = x;
              finalY = y;
              found = true;
              break outerLoop;
            }
          }
        }
      }
    }

    // 应用最终位置
    item.gridX = finalX;
    item.gridY = finalY;
  }

  draggedItem.value = null;
  document.removeEventListener('mousemove', handleDragMove);
  document.removeEventListener('mouseup', handleDragEnd);

  // 强制触发响应式更新
  layoutItems.value = [...layoutItems.value];
};

// 调整大小
const startResize = (event: MouseEvent, item: LayoutItem, handle: string) => {
  if (!isEditMode.value) return;

  resizingItem.value = item;
  resizeHandle.value = handle;

  document.addEventListener('mousemove', handleResizeMove);
  document.addEventListener('mouseup', handleResizeEnd);
  event.stopPropagation();
  event.preventDefault();
};

const handleResizeMove = (event: MouseEvent) => {
  if (!resizingItem.value || !workspaceRef.value) return;

  const rect = workspaceRef.value.getBoundingClientRect();
  const mouseX = event.clientX - rect.left;
  const mouseY = event.clientY - rect.top;

  const item = resizingItem.value;
  const component = availableComponents.find((c) => c.type === item.type);
  const minWidth = component?.minGridWidth || 4;
  const minHeight = component?.minGridHeight || 4;

  // 保存当前值，用于碰撞检测失败时恢复
  const originalX = item.gridX;
  const originalY = item.gridY;
  const originalWidth = item.gridWidth;
  const originalHeight = item.gridHeight;

  let newX = originalX;
  let newY = originalY;
  let newWidth = originalWidth;
  let newHeight = originalHeight;

  if (resizeHandle.value.includes('right')) {
    newWidth = Math.max(
      minWidth,
      Math.min(pixelToGrid(mouseX) - item.gridX, GRID_COLUMNS - item.gridX),
    );
  }
  if (resizeHandle.value.includes('bottom')) {
    newHeight = Math.max(minHeight, pixelToGrid(mouseY) - item.gridY);
  }
  if (resizeHandle.value.includes('left')) {
    const newGridX = pixelToGrid(mouseX);
    const calculatedWidth = originalWidth + (originalX - newGridX);
    if (calculatedWidth >= minWidth && newGridX >= 0) {
      newX = newGridX;
      newWidth = calculatedWidth;
    }
  }
  if (resizeHandle.value.includes('top')) {
    const newGridY = pixelToGrid(mouseY);
    const calculatedHeight = originalHeight + (originalY - newGridY);
    if (calculatedHeight >= minHeight && newGridY >= 0) {
      newY = newGridY;
      newHeight = calculatedHeight;
    }
  }

  // 碰撞检测 - 只有不碰撞时才应用新的尺寸和位置
  if (!checkCollision(item, newX, newY, newWidth, newHeight)) {
    item.gridX = newX;
    item.gridY = newY;
    item.gridWidth = newWidth;
    item.gridHeight = newHeight;
  }
};

const handleResizeEnd = () => {
  resizingItem.value = null;
  resizeHandle.value = '';
  document.removeEventListener('mousemove', handleResizeMove);
  document.removeEventListener('mouseup', handleResizeEnd);
};

const selectItem = (item: LayoutItem) => {
  selectedItem.value = selectedItem.value?.id === item.id ? null : item;
};

const removeItem = (event: Event, id: string) => {
  event.stopPropagation();
  event.preventDefault();
  const index = layoutItems.value.findIndex((item) => item.id === id);
  if (index !== -1) {
    layoutItems.value.splice(index, 1);
    if (selectedItem.value?.id === id) {
      selectedItem.value = null;
    }
    ElMessage.success('组件已删除');
  }
};

const removeSelectedItem = () => {
  if (selectedItem.value) {
    removeItem(new Event('click'), selectedItem.value.id);
  }
};

const configureItem = (event: Event, item: LayoutItem) => {
  event.stopPropagation();
  event.preventDefault();
  currentConfigItem.value = item;
  configDialogVisible.value = true;
};

const saveItemConfig = () => {
  configDialogVisible.value = false;
  ElMessage.success('配置已保存');
};

const saveLayout = () => {
  localStorage.setItem(
    'custom-workspace-layout',
    JSON.stringify(layoutItems.value),
  );
  // 保存后更新备份，这样退出设计模式时就不会恢复了
  layoutBackup.value = JSON.parse(JSON.stringify(layoutItems.value));
  ElMessage.success('布局已保存');
};

const cancelChanges = () => {
  // 恢复到进入设计模式前的状态
  layoutItems.value = JSON.parse(JSON.stringify(layoutBackup.value));
  selectedItem.value = null;
  ElMessage.success('已恢复到进入设计模式前的状态');
};

const loadLayout = () => {
  try {
    const saved = localStorage.getItem('custom-workspace-layout');
    if (saved) {
      layoutItems.value = JSON.parse(saved);
    } else {
      loadDefaultLayout();
    }
    // 加载布局后，初始化备份（这样第一次进入设计模式时就有正确的备份）
    layoutBackup.value = JSON.parse(JSON.stringify(layoutItems.value));
  } catch (error) {
    console.error('Failed to load layout:', error);
    loadDefaultLayout();
    // 出错时也要初始化备份
    layoutBackup.value = structuredClone(layoutItems.value);
  }
};

const loadDefaultLayout = () => {
  layoutItems.value = [
    {
      id: 'user-stats-default',
      type: 'user-stats',
      gridX: 0,
      gridY: 0,
      gridWidth: 6,
      gridHeight: 6,
      config:
        availableComponents.find((c) => c.type === 'user-stats')
          ?.defaultConfig || {},
    },
    {
      id: 'revenue-stats-default',
      type: 'revenue-stats',
      gridX: 6,
      gridY: 0,
      gridWidth: 6,
      gridHeight: 6,
      config:
        availableComponents.find((c) => c.type === 'revenue-stats')
          ?.defaultConfig || {},
    },
    {
      id: 'order-stats-default',
      type: 'order-stats',
      gridX: 12,
      gridY: 0,
      gridWidth: 6,
      gridHeight: 6,
      config:
        availableComponents.find((c) => c.type === 'order-stats')
          ?.defaultConfig || {},
    },
    {
      id: 'sales-trend-default',
      type: 'sales-trend',
      gridX: 0,
      gridY: 6,
      gridWidth: 12,
      gridHeight: 10,
      config:
        availableComponents.find((c) => c.type === 'sales-trend')
          ?.defaultConfig || {},
    },
    {
      id: 'daily-tasks-default',
      type: 'daily-tasks',
      gridX: 12,
      gridY: 6,
      gridWidth: 8,
      gridHeight: 12,
      config:
        availableComponents.find((c) => c.type === 'daily-tasks')
          ?.defaultConfig || {},
    },
  ];
  // 加载默认布局后也要更新备份
  layoutBackup.value = structuredClone(layoutItems.value);
};

const resetLayout = () => {
  layoutItems.value = [];
  ElMessage.success('布局已清空');
};

// 计算画布所需的最小高度 - 响应式
const canvasHeight = computed(() => {
  if (layoutItems.value.length === 0) {
    // 空画布时使用合理的高度：8-12行，最少400px，最多800px
    const calculatedHeight = gridUnitSize.value * 10; // 10行高度
    return Math.max(400, Math.min(800, calculatedHeight));
  }

  const validItems = layoutItems.value.filter(
    (item) => item.gridY !== null && item.gridHeight !== null,
  );

  if (validItems.length === 0) {
    const calculatedHeight = gridUnitSize.value * 10;
    return Math.max(400, Math.min(800, calculatedHeight));
  }

  const maxBottom = Math.max(
    ...validItems.map((item) => item.gridY + item.gridHeight),
  );

  // 画布高度刚好到最底部组件，不留空白
  const height = gridUnitSize.value * maxBottom;

  // 临时调试信息

  return height;
});

// 组件映射
const componentMap = {
  'sales-trend': ChartCard,
  'channel-analysis': ChartCard,
  'user-stats': InfoCard,
  'revenue-stats': InfoCard,
  'order-stats': InfoCard,
  'daily-tasks': TodoCard,
  'weather-info': WeatherCard,
};

const configComponentMap = {
  'sales-trend': ChartCardConfig,
  'channel-analysis': ChartCardConfig,
  'user-stats': InfoCardConfig,
  'revenue-stats': InfoCardConfig,
  'order-stats': InfoCardConfig,
  'daily-tasks': TodoCardConfig,
  'weather-info': WeatherCardConfig,
};

const getConfigComponentByType = (type: string) => {
  return configComponentMap[type as keyof typeof configComponentMap];
};

// 窗口大小变化时强制刷新
const forceRefresh = ref(0);
let resizeTimer: null | number = null;
let resizeObserver: null | ResizeObserver = null;

const handleResize = () => {
  // 防抖处理，避免频繁重新计算
  if (resizeTimer) {
    clearTimeout(resizeTimer);
  }
  resizeTimer = window.setTimeout(() => {
    // 强制重新计算栅格大小
    forceRefresh.value++;
    resizeTimer = null;
  }, 100); // 100ms 防抖延迟
};

const handleKeyDown = (event: KeyboardEvent) => {
  if (!isEditMode.value) return;

  if (event.key === 'Delete' && selectedItem.value) {
    removeSelectedItem();
    event.preventDefault();
  }

  if (event.key === 'Escape') {
    selectedItem.value = null;
    event.preventDefault();
  }
};

// 监听画布宽度变化，确保响应式更新
watch(
  canvasWidth,
  (newWidth, oldWidth) => {
    if (newWidth !== oldWidth) {
      // 画布宽度变化时，强制重新计算所有组件位置
      layoutItems.value = [...layoutItems.value];
    }
  },
  { immediate: false },
);

// 生命周期
onMounted(async () => {
  loadLayout();
  // 监听窗口大小变化
  window.addEventListener('resize', handleResize);
  // 监听键盘事件
  document.addEventListener('keydown', handleKeyDown);

  // 等待 DOM 渲染完成后设置 ResizeObserver
  await nextTick();

  // 使用 ResizeObserver 监听容器大小变化
  if (workspaceRef.value) {
    resizeObserver = new ResizeObserver((entries) => {
      for (const entry of entries) {
        // 当容器大小变化时                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 立即触发重新计算
        forceRefresh.value++;
        // 同时使用防抖处理，避免过于频繁的更新
        handleResize();
      }
    });
    resizeObserver.observe(workspaceRef.value);
  } else {
    // 如果 ResizeObserver 设置失败，使用定时器作为备选方案
    console.warn('ResizeObserver setup failed, using fallback timer');
    setInterval(() => {
      handleResize();
    }, 500);
  }
});

onUnmounted(() => {
  // 清理事件监听器
  window.removeEventListener('resize', handleResize);
  document.removeEventListener('keydown', handleKeyDown);

  // 清理 ResizeObserver
  if (resizeObserver) {
    resizeObserver.disconnect();
    resizeObserver = null;
  }
});
</script>

<template>
  <div class="custom-workspace p-4">
    <!-- 工具栏 -->
    <Toolbar
      :is-edit-mode="isEditMode"
      :selected-item="selectedItem"
      :has-unsaved-changes="hasUnsavedChanges()"
      :grid-unit-size="gridUnitSize"
      :canvas-width="canvasWidth"
      :available-components="availableComponents"
      :layout-items="layoutItems"
      @toggle-edit-mode="toggleEditMode"
      @save-layout="saveLayout"
      @cancel-changes="cancelChanges"
      @remove-selected-item="removeSelectedItem"
      @reset-layout="resetLayout"
      @load-default-layout="loadDefaultLayout"
    />

    <!-- 组件库面板 - 横向布局 -->
    <ComponentPanel
      v-if="isEditMode"
      :available-components="availableComponents"
      @drag-start="handleDragStart"
    />

    <!-- 设计画布容器 -->
    <div
      ref="workspaceRef"
      class="workspace-container rounded-lg border-2 border-dashed border-gray-300 bg-gray-50 p-4"
      :class="{ 'border-blue-400 bg-blue-50': isEditMode }"
    >
      <!-- 实际画布 - 固定宽度 -->
      <Canvas
        :is-edit-mode="isEditMode"
        :layout-items="layoutItems"
        :grid-unit-size="gridUnitSize"
        :canvas-height="canvasHeight"
        :selected-item="selectedItem"
        :dragged-item="draggedItem"
        :component-map="componentMap"
        @drop="handleDrop"
        @dragover="handleDragOver"
        @start-drag="startDrag"
        @configure-item="configureItem"
        @remove-item="removeItem"
        @start-resize="startResize"
      />
    </div>

    <!-- 组件配置弹窗 -->
    <ElDialog v-model="configDialogVisible" title="组件配置" width="600px">
      <component
        v-if="currentConfigItem"
        :is="getConfigComponentByType(currentConfigItem.type)"
        v-model:config="currentConfigItem.config"
      />
      <template #footer>
        <ElButton @click="configDialogVisible = false">取消</ElButton>
        <ElButton type="primary" @click="saveItemConfig">确定</ElButton>
      </template>
    </ElDialog>
  </div>
</template>

<style scoped>
.custom-workspace {
  min-height: calc(100vh - 120px);
}

.workspace-container {
  /* 移除固定最小高度，让画布动态调整 */
}
</style>